/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.commons;

import io.iec.edp.caf.commons.runtime.CafEnvironment;
import io.iec.edp.caf.commons.runtime.env.enums.StartupMode;
import io.iec.edp.caf.commons.spi.AppManagerResolver;
import io.iec.edp.caf.msu.common.manager.AppManager;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.util.Assert;

import java.lang.annotation.Annotation;
import java.net.URLClassLoader;
import java.util.*;

/**
 * 应用程序ClassLoader管理器，为了兼容串行和并行两种情况
 */
@Slf4j
public class ApplicationClassLoaderManager {
    private static List<AppManagerResolver> appManagerResolvers = new ArrayList<>();

    static {
        if(CafEnvironment.getStartupMode() != StartupMode.Serial){
            ServiceLoader<AppManagerResolver> operations = ServiceLoader.load(AppManagerResolver.class);
            for (AppManagerResolver operation : operations) {
                appManagerResolvers.add(operation);
            }

            Assert.isTrue(!appManagerResolvers.isEmpty(),"Parallel Start Mode,But can not get any [AppManagerResolver],Please check");
        }

    }

    /**
     * 获取环境里包含指定Annotation的class
     * @param annotation 注解类型
     * @return 包含指定注解的类型集合
     */
    public static Set<Class<?>> getClassesWithAnnotation(Class<? extends Annotation> annotation) {
        if(log.isDebugEnabled()){
            log.debug("current startup mode ["+ CafEnvironment.getStartupMode()+"]");
            log.debug("appManagerResolvers size ["+ appManagerResolvers.size()+"]");
        }
        Set<Class<?>> result = new HashSet<>();

        if(CafEnvironment.getStartupMode() != StartupMode.Serial){
            if( !appManagerResolvers.isEmpty() ) {
                var resolver = appManagerResolvers.get(0);
                if(resolver!=null){
                    var temp = resolver.getClassesWithAnnotation(annotation);
                    if(log.isDebugEnabled()){
                        log.debug("current annotation ["+(annotation!=null?annotation.getName():null)+"]");
                        log.debug("in parallel startup,get class count ["+(temp!=null?temp.size():0)+"]");
                    }
                    if( temp != null && !temp.isEmpty() ) {
                        result.addAll(temp);
                    }
                }
            }

        }else{
            result  = AppManager.getClassesWithAnnotation(annotation);
        }

        return result;
    }


    /**
     * 根据启动模式获取对应的ClassLoader
     * @param mode 启动模式，不传该参数默认是串行模式
     * @return 类加载器
     */
    public static ClassLoader getCafClassLoader(StartupMode mode) {
        ClassLoader cl = null;
        if (mode == null) {
            mode = StartupMode.Serial;
        }
        switch (mode) {
            case Parallel:
                cl = getServiceClassLoader();
                break;
            case Serial:
            default:
                cl = AppManager.getCafClassLoader();
        }
        if (log.isDebugEnabled()) {
            log.debug("getCafClassLoader current classloader type [" + cl.getClass().getName() + "]");
        }
        return cl;
    }

    /**
     * 获取不同SU的ClassPath
     * @param su 微服务单元名称
     * @return 微服务单元类加载器
     */
    public static URLClassLoader getSuClasspath(String su) {
        if(log.isDebugEnabled()){
            log.debug("current startup mode ["+CafEnvironment.getStartupMode()+"]");
        }

        if(CafEnvironment.getStartupMode() == StartupMode.Parallel){
            URLClassLoader urlClassLoader = null;
            if( !appManagerResolvers.isEmpty() ) {
                var resolver = appManagerResolvers.get(0);
                if(resolver!=null){
                    urlClassLoader = resolver.getSuClasspath(su);
                }
            }
            return urlClassLoader;
        }else{
            return AppManager.getCafClassLoader().getSuClasspath(su);
        }
    }

    //非并行启动下直接获取当前classloader，并行启动下获取PlatformClassloader的parent
    public static ClassLoader getServiceClassLoader(){
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        //迭代寻找需要的classloader
        while(cl!=null){
            //不直接对classloader进行依赖 对类名进行强匹配
            //如果识别为并行启动 则加载parent
            if(cl.getClass().getName().contains("PlatformClassloader")){
                return cl.getParent();
            }
            //如果识别为非并行启动 则返回CafClassLoader
            if(cl.getClass().getName().contains("CAFClassLoader")){
                return cl;
            }
            cl = cl.getParent();
        }
        return Thread.currentThread().getContextClassLoader();
    }
}
